﻿using System;
using RayDen.Library.Components.Surface;
using RayDen.Library.Core;
using RayDen.Library.Core.Primitives;
using RayDen.Library.Entity.Scene;

using RayDen.RayEngine.Core.Types;

namespace RayDen.RayEngine.Core.Surface
{
    public class MatteLambertBrdf : BaseBxdf
    {
        public MatteLambertBrdf() { }
        public MatteLambertBrdf(ref RayHit rh, ref RayData ray, ref Normal ng, ref Normal ns, ref UV texCoord, MaterialInfo mi, SurfaceTextureInfo texData, bool fromLight)
            : base(ref rh, ref ray, ref ng, ref ns, ref texCoord, mi, texData, fromLight)
        {
        }

        public override BrdfType Type
        {
            get
            {
                return BrdfType.Diffuse | BrdfType.Reflection;
            }
        }

        public override bool IsDelta
        {
            get { return false; }
        }

        public override bool IsLightSource()
        {
            return false;
        }

        public override bool IsDiffuse()
        {
            return true;
        }

        public override bool IsRefractive()
        {
            return false;
        }

        public override bool IsSpecular()
        {
            return false;
        }

        protected override RgbSpectrum Sample(ref HitPointInfo HitPoint, ref Vector localFixedDir, out Vector localSampledDir, float u0, float u1, out float pdfW, out float absCosDir, out BsdfEvent _event)
        {
            absCosDir = 0f;
            _event = BsdfEvent.Diffuse | BsdfEvent.Reflect;
            pdfW = 0f;
            localSampledDir = new Vector();
            if (Math.Abs(localFixedDir.z) < MathLab.COS_EPSILON_STATIC)
                return RgbSpectrum.ZeroSpectrum();

            localSampledDir = Sgn(localFixedDir.z) * MC.CosineSampleHemisphere(u0, u1, out pdfW);

            absCosDir = Math.Abs(localSampledDir.z);
            if (absCosDir < MathLab.COS_EPSILON_STATIC)
                return RgbSpectrum.ZeroSpectrum();

            var kd = (RgbSpectrum)(TexData.Diffuse);
            kd.Mul(MathLab.INVPI);
            return (kd);
        }

        protected override RgbSpectrumInfo Evaluate(ref HitPointInfo HitPoint, ref Vector localLightDir, ref Vector localEyeDir, out BsdfEvent _event, out float directPdfW, out float reversePdfW)
        {
            _event = BsdfEvent.Diffuse | BsdfEvent.Reflect;
            directPdfW = Math.Abs((HitPoint.FromLight ? localEyeDir.z : localLightDir.z) * MathLab.INVPI);
            reversePdfW = Math.Abs((HitPoint.FromLight ? localLightDir.z : localEyeDir.z) * MathLab.INVPI);
            var kd = TexData.Diffuse;
            return (kd * MathLab.INVPI);
        }
    }
}